
#include "CListCtrlEx.h"


/************************************************************************************************/
/*									CHeaderCtrlEx													*/
/************************************************************************************************/

IMPLEMENT_DYNAMIC(CHeaderCtrlEx, CHeaderCtrl)

CHeaderCtrlEx::CHeaderCtrlEx()
: m_R(200), m_G(200), m_B(200)
, m_Gradient(2)
{
	m_Format = "";
	m_Height = 1;
	m_fontHeight = 0;
	m_fontWith = 0;
	m_color = RGB(0,0,0);
}

CHeaderCtrlEx::~CHeaderCtrlEx()
{
}


BEGIN_MESSAGE_MAP(CHeaderCtrlEx, CHeaderCtrl)
	ON_WM_PAINT()
	ON_MESSAGE(HDM_LAYOUT, OnLayout)
END_MESSAGE_MAP()

// CHeaderCtrlEx 消息处理程序

void CHeaderCtrlEx::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	// TODO: 在此处添加消息处理程序代码
	// 不为绘图消息调用 CHeaderCtrl::OnPaint()
	int nItem; 
	nItem = GetItemCount();//得到有几个单元 
	for(int i = 0; i<nItem;i ++) 
	{ 
		CRect tRect;
		GetItemRect(i,&tRect);//得到Item的尺寸
		int R = m_R,G = m_G,B = m_B;
		CRect nRect(tRect);//拷贝尺寸到新的容器中 
		nRect.left++;//留出分割线的地方 
		//绘制立体背景 
		for(int j = tRect.top;j<=tRect.bottom;j++) 
		{ 
			nRect.bottom = nRect.top+1; 
			CBrush _brush; 
			_brush.CreateSolidBrush(RGB(R,G,B));//创建画刷 
			dc.FillRect(&nRect,&_brush); //填充背景 
			_brush.DeleteObject(); //释放画刷 
			R-=m_Gradient;G-=m_Gradient;B-=m_Gradient;
			if (R<0)R = 0;
			if (G<0)G = 0;
			if (B<0)B= 0;
			nRect.top = nRect.bottom; 
		} 
		dc.SetBkMode(TRANSPARENT);
		CFont nFont ,* nOldFont; 
		//dc.SetTextColor(RGB(250,50,50)); 
		dc.SetTextColor(m_color);
		nFont.CreateFont(m_fontHeight,m_fontWith,0,0,0,FALSE,FALSE,0,0,0,0,0,0,_TEXT("宋体"));//创建字体 
		nOldFont = dc.SelectObject(&nFont);

		UINT nFormat = 1;
		if (m_Format[i]=='0')
		{
			nFormat = DT_LEFT;
			tRect.left+=3;
		}
		else if (m_Format[i]=='1')
		{
			nFormat = DT_CENTER;
		}
		else if (m_Format[i]=='2')
		{
			nFormat = DT_RIGHT;
			tRect.right-=3;
		}
		TEXTMETRIC metric;
		dc.GetTextMetrics(&metric);
		int ofst = 0;
		ofst = tRect.Height() - metric.tmHeight;
		tRect.OffsetRect(0,ofst/2);
		dc.DrawText(m_HChar[i],&tRect,nFormat);
		dc.SelectObject(nOldFont); 
		nFont.DeleteObject(); //释放字体 
	} 
	//画头部剩余部分
	CRect rtRect;
	CRect clientRect;
	GetItemRect(nItem - 1,rtRect);
	GetClientRect(clientRect);
	rtRect.left = rtRect.right+1;
	rtRect.right = clientRect.right;
	int R = m_R,G = m_G,B = m_B;
	CRect nRect(rtRect);
	//绘制立体背景 
	for(int j = rtRect.top;j<=rtRect.bottom;j++) 
	{ 
		nRect.bottom = nRect.top+1; 
		CBrush _brush; 
		_brush.CreateSolidBrush(RGB(R,G,B));//创建画刷 
		dc.FillRect(&nRect,&_brush); //填充背景 
		_brush.DeleteObject(); //释放画刷 
		R-=m_Gradient;G-=m_Gradient;B-=m_Gradient;
		if (R<0)R = 0;
		if (G<0)G = 0;
		if (B<0)B= 0;
		nRect.top = nRect.bottom; 
	} 
}
LRESULT CHeaderCtrlEx::OnLayout( WPARAM wParam, LPARAM lParam )
{
	LRESULT lResult = CHeaderCtrl::DefWindowProc(HDM_LAYOUT, 0, lParam); 
	HD_LAYOUT &hdl = *( HD_LAYOUT * ) lParam; 
	RECT *prc = hdl.prc; 
	WINDOWPOS *pwpos = hdl.pwpos; 

	//表头高度为原来1.5倍，如果要动态修改表头高度的话，将1.5设成一个全局变量 
	int nHeight = (int)(pwpos->cy * m_Height);
	pwpos->cy = nHeight; 
	prc->top = nHeight; 
	return lResult; 
}



/************************************************************************************************/
/*									CListCtrlEx													*/
/************************************************************************************************/

CListCtrlEx::CListCtrlEx()
{
	this->mFont=NULL;
	m_pListener = NULL;
	m_CellEditMask=0;
	memset(&m_curCCtrl, 0, sizeof(m_curCCtrl));
	
	m_defClrText=RGB(0,0,0);
	m_defClrTextBk=RGB(255,255,255);
}

CListCtrlEx::~CListCtrlEx()
{
	delete mFont;
	this->mFont=NULL;
	std::map<int, CCtrl>::iterator it = m_mapCtrl.begin();
	for (; it != m_mapCtrl.end(); it++)
	{
		delete it->second.pCtrl;
	}
	m_mapCtrl.clear();
}

void CListCtrlEx::SetListener(Listener *pListener)
{
	m_pListener = pListener;
}

BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
	ON_WM_LBUTTONDOWN()
	//自定义
	ON_EN_KILLFOCUS(IDC_CELLEDIT, OnCellCtrlEnd)
	ON_CBN_KILLFOCUS(IDC_CELLEDIT, OnCellCtrlEnd)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, &CListCtrlEx::OnLvnColumnclick)
//	ON_NOTIFY_REFLECT(LVN_BEGINSCROLL, &CListCtrlEx::OnLvnBeginScroll)
	ON_WM_VSCROLL()
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw)
	ON_NOTIFY_REFLECT(LVN_DELETEALLITEMS, OnDeleteallitems)
	ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteitem)
	ON_NOTIFY_REFLECT(LVN_INSERTITEM, OnInsertitem)
END_MESSAGE_MAP()

void CListCtrlEx::OnCellCtrlEnd()
{
	if (m_curCCtrl.pCCtrl == NULL || m_curCCtrl.pCCtrl->eType==ECtrl::ClkText)
		return;

	if (!HideCCtrl())
		return;

	CString text;
	m_curCCtrl.pCCtrl->pCtrl->GetWindowText(text);

	int val = 0;
	if (m_curCCtrl.pCCtrl->eType == CListCtrlEx::ECtrl::ComboBox)
		val = ((CComboBox*)m_curCCtrl.pCCtrl->pCtrl)->GetCurSel();

	this->SetItemText(m_curCCtrl.iRow, m_curCCtrl.iCol, text.GetBuffer());

	if (m_pListener != NULL)
		m_pListener->OnEditEnd(this, m_curCCtrl.iRow, m_curCCtrl.iCol, m_curCCtrl.pCCtrl->pCtrl, text.GetBuffer(), val);
	

	//TCHAR wstr[20]={0};
	//int val = 0;
	//if(mCellCtrls.find(mSelCol)==mCellCtrls.end())
	//	return;
	//BOOL b = mCellCtrls[mSelCol].mCtrl->IsWindowVisible();
	//if (!b)return;
	//::GetWindowText(mCellCtrls[mSelCol].mCtrl->m_hWnd, wstr, sizeof(wstr));
	//ShowCellCtrl(FALSE);
	//if(mCellCtrls[mSelCol].mType==CListCtrlEx::Ctrl_ComboBox)
	//	val = ((CComboBox*)mCellCtrls[mSelCol].mCtrl)->GetCurSel();
	//this->SetItemText(mSelRow,mSelCol,wstr);
	//if(mListener!=NULL)
	//	mListener->OnListCtrlExEndEdit(mSelRow,mSelCol,wstr,val);
}


void CListCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
{
	//RECT rtView = {0};
	//this->GetClientRect(&rtView);
	//InvalidateRect(&rtView, TRUE);
	//::SendMessage(this->m_hWnd,WM_KILLFOCUS,0,0);//禁止获得焦点，出现蓝底影响美观
	
	OnCellCtrlEnd();

	int row = this->GetTopIndex();
	int last_visible_index = row + this->GetCountPerPage();
	if (last_visible_index > this->GetItemCount())
		last_visible_index = this->GetItemCount();

	while (row <= last_visible_index)//遍历所有行[item]
	{
		CRect itemRect;
		if(this->GetItemRect(row, &itemRect, LVIR_BOUNDS))
		{
			if(itemRect.PtInRect(point))
			{
				bool isEditEvent = false;
				//搜寻具体点击Cell，启用编辑控件
				CRect subRect;
				int colCount=this->GetHeaderCtrl()->GetItemCount();
				for(int i=0;i<colCount;i++)//遍历所有列[subItem]
				{
					if (i != 0 && m_mapCtrl.find(i) == m_mapCtrl.end())//eliminate the 1st and end col
						continue;
					else if(GetSubItemRect(row,i,LVIR_LABEL , subRect))
					{
						//GetDC()->Draw3dRect(&subRect,RGB(100,100,100),RGB(100,100,100));
						if(i==0)//deal with the 1st col.
						{
							if(point.x<subRect.left && point.x>0)
							{
								isEditEvent = true;
								//先传递消息，放在this->GetCheck(row);之前，否则得到的消息可能不准确
								CListCtrl::OnLButtonDown(nFlags, point);
								if(m_pListener!=NULL)
									m_pListener->OnChecked(this, row, this->GetCheck(row));
								break;
							}
						}
						else if(subRect.PtInRect(point))// deal with the other cols
						{
							isEditEvent = true;
							CString cstr = this->GetItemText(row, i);
							this->EnableCellEdit(row, i, subRect, cstr);
							this->SetItemState(row, 0, LVIS_FOCUSED|LVIS_SELECTED);//禁止获得焦点，出现蓝底影响美观
							break;
						}
					}
				}
				this->SetSelectionMark(row); // xktesla@2020-9-5 17:33:45 暂未验证
				if (!isEditEvent && m_pListener)  m_pListener->OnItemLClick(this, row);

				//添加行选中效果
				DrawSelEffect(itemRect);
				break;
			}
		}
		row++;
	}
}

void CListCtrlEx::DrawSelEffect(RECT rt)
{
	if (memcmp(&rt,&mOldRect,sizeof(RECT)) != 0)
	{
		InvalidateRect(&mOldRect, FALSE);
	}
	//rt.top -= 1;
	//rt.right += 1;
	//rt.bottom += 1;
	//this->GetDC()->DrawEdge(&rt, EDGE_SUNKEN, BF_RECT);
	this->GetDC()->Draw3dRect(&rt, RGB(0, 0, 255), RGB(0, 0, 255));
	mOldRect=rt;
}

bool CListCtrlEx::HideCCtrl()
{
	bool bFind = false;
	std::map<int, CCtrl>::iterator it = m_mapCtrl.begin();
	for (; it != m_mapCtrl.end(); it++)
	{
		if (it->second.pCtrl->IsWindowVisible())
		{
			bFind = true;
			it->second.pCtrl->ShowWindow(SW_HIDE);
		}
	}
	return bFind;
}

CWnd *CListCtrlEx::BindCtrl(int col,ECtrl type)
{
	CWnd *pCtrl=NULL;
	switch(type)
	{
	case CListCtrlEx::ECtrl::Edit:
		{
			pCtrl=new CEdit();
			((CEdit *)pCtrl)->Create(WS_CHILD|WS_BORDER|/*ES_UPPERCASE|*/WS_VISIBLE,CRect(),this, 100);
			//pCtrl->SubclassWindow(this->GetSafeHwnd());
		}break;
	case CListCtrlEx::ECtrl::ComboBox:
		{
			pCtrl=new CComboBox();
			((CComboBox *)pCtrl)->Create(WS_CHILD|CBS_DROPDOWNLIST |WS_VISIBLE|WS_VSCROLL|WS_HSCROLL,CRect(0,0,0,100),this, 101);
	}break;
	case CListCtrlEx::ECtrl::ClkText:
	{
		pCtrl = new CStatic();
		((CStatic *)pCtrl)->Create("",WS_CHILD | CBS_DROPDOWNLIST | WS_VISIBLE, CRect(0, 0, 0, 100), this, 102);
	}break;
	}
	if(pCtrl!=NULL)
	{
		if(this->mFont==NULL)
		{
			LOGFONT logFont;
			this->mFont=new CFont();
			this->GetFont()->GetLogFont(&logFont);
			logFont.lfHeight=11;
			logFont.lfWidth=5;
			this->mFont->CreateFontIndirect(&logFont);
		}
		//pCtrl->SetParent(this);
		pCtrl->SetDlgCtrlID(IDC_CELLEDIT);
		pCtrl->SetFont(this->mFont);
		CCtrl ctrl;
		ctrl.pCtrl = pCtrl;
		ctrl.eType = type;
		m_mapCtrl[col] = ctrl;
	}
	return pCtrl;
}

void CListCtrlEx::EnableCellEdit(int row, int col, CRect rect, CString text)
{
	if (m_mapCtrl.find(col)!=m_mapCtrl.end())
	{
		m_curCCtrl.iRow = row;
		m_curCCtrl.iCol = col;
		m_curCCtrl.pCCtrl = &m_mapCtrl[col];
		switch (m_mapCtrl[col].eType)
		{
			case CListCtrlEx::ECtrl::Edit:
			{
				((CEdit *)m_mapCtrl[col].pCtrl)->SetWindowText(text);
			}break;
			case CListCtrlEx::ECtrl::ComboBox:
			{
				((CComboBox *)m_mapCtrl[col].pCtrl)->SelectString(0, text);
			}break;
			case CListCtrlEx::ECtrl::ClkText:
			{
				if (m_pListener) m_pListener->OnEditEnd(this, row, col, m_curCCtrl.pCCtrl->pCtrl, text.GetBuffer(0), 0);
			}break;
			default:return;
		}
		//this->GetDC()->Draw3dRect( &subRect, RGB(0, 0, 255), RGB(0, 0, 255));
		m_curCCtrl.pCCtrl->pCtrl->ShowWindow(SW_SHOW);
		//rect.DeflateRect(1,1,1,1);
		m_curCCtrl.pCCtrl->pCtrl->MoveWindow(rect, TRUE);
		m_curCCtrl.pCCtrl->pCtrl->SetFocus();
	}
}

void CListCtrlEx::OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	OnCellCtrlEnd();
	*pResult = 0;
}

void CListCtrlEx::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	OnCellCtrlEnd();
	CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CListCtrlEx::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
	*pResult = CDRF_DODEFAULT;
	NMLVCUSTOMDRAW * lplvdr=(NMLVCUSTOMDRAW*)pNMHDR;
	NMCUSTOMDRAW &nmcd = lplvdr->nmcd;
	switch(lplvdr->nmcd.dwDrawStage)//判断状态
	{
		case CDDS_PREPAINT:
		{
			*pResult = CDRF_NOTIFYITEMDRAW;
		}break;
		case CDDS_ITEMPREPAINT:
		{
			*pResult = CDRF_NOTIFYSUBITEMDRAW;
		}break;
		case CDDS_ITEMPREPAINT | CDDS_SUBITEM://如果为画ITEM之前就要进行颜色的改变
		{
			lplvdr->clrTextBk=m_clrData[nmcd.dwItemSpec][lplvdr->iSubItem].clrTextBk;
			lplvdr->clrText=m_clrData[nmcd.dwItemSpec][lplvdr->iSubItem].clrText;
		}break;
	}
}

/*******************************************新函数*****************************************/

BOOL CListCtrlEx::SetTextColor(int iItem,int subItem,COLORREF rgb)
{
	int colCnt=GetHeaderCtrl()->GetItemCount();
	int rowCnt=GetItemCount();

	if(iItem<0 && subItem<0)
	{
		for(int row=0;row<rowCnt;row++)
		{
			for(int col=0;col<colCnt;col++)
				m_clrData[row][col].clrText=rgb;
		}
		return RedrawItems(0,rowCnt);
	}
	else if(iItem<0)
	{
		for(int row=0;row<rowCnt;row++)
			m_clrData[row][subItem].clrText=rgb;

		return RedrawItems(0,rowCnt);
	}
	else if(subItem<0)
	{
		for(int col=0;col<colCnt;col++)
			m_clrData[iItem][col].clrText=rgb;
		return RedrawItems(iItem,iItem);
	}
	else
	{
		m_clrData[iItem][subItem].clrText=rgb;
		return RedrawItems(iItem,iItem);
	}
}

BOOL CListCtrlEx::SetCellColor(int iItem, int subItem, COLORREF rgb)
{
	int colCnt=GetHeaderCtrl()->GetItemCount();
	int rowCnt=GetItemCount();

	if(iItem<0 && subItem<0)
	{
		for(int row=0;row<rowCnt;row++)
		{
			for(int col=0;col<colCnt;col++)
				m_clrData[row][col].clrTextBk=rgb;
		}
		return RedrawItems(0,rowCnt);
	}
	else if(iItem<0)
	{
		for(int row=0;row<rowCnt;row++)
			m_clrData[row][subItem].clrTextBk=rgb;

		return RedrawItems(0,rowCnt);
	}
	else if(subItem<0)
	{
		for(int col=0;col<colCnt;col++)
			m_clrData[iItem][col].clrTextBk=rgb;
		return RedrawItems(iItem,iItem);
	}
	else
	{
		m_clrData[iItem][subItem].clrTextBk=rgb;
		return RedrawItems(iItem,iItem);
	}
}

void CListCtrlEx::OnDeleteitem(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	std::vector<std::vector<DRAWPEN>>::iterator it=m_clrData.begin();
	for(;it<m_clrData.end();it++)
	{
		if((DRAWPEN*)(&(*it)) == (DRAWPEN*)(&m_clrData[pNMLV->iItem]))
		{
			m_clrData.erase(it);
			break;
		}
	}

	*pResult = 0;
}

void CListCtrlEx::OnInsertitem(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

	std::vector<DRAWPEN> data;
	data.resize(GetHeaderCtrl()->GetItemCount());
	for(uint32_t i=0;i<data.size();i++)
	{
		data[i].clrText=m_defClrText;
		data[i].clrTextBk=m_defClrTextBk;
	}
	//m_clrData[pNMLV->iItem]=data;
	//m_clrData.push_back(data);
	std::vector<std::vector<DRAWPEN>>::iterator it=m_clrData.begin();
	for(;it<m_clrData.end() && pNMLV->iItem<m_clrData.size();it++)
	{
		if((int)(&(*it))==(int)(&m_clrData[pNMLV->iItem]))
		{
			m_clrData.insert(it,data);
			break;
		}
		
	}
	if(it==m_clrData.end() || pNMLV->iItem>=m_clrData.size())
		m_clrData.push_back(data);

	std::map<int, CCtrl>::iterator itFind = m_mapCtrl.find(pNMLV->iSubItem);
	if (itFind != m_mapCtrl.end() && itFind->second.eType == ECtrl::ClkText)
	{
	}

	*pResult = 0;
}

void CListCtrlEx::OnDeleteallitems(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	m_clrData.clear();
	*pResult = 0;
}